5.2 算法约定(Algorithm Conventions)
规范常常使用一个带编号的列表来显示算法中的步骤。这个小算法被用作准确地表达ECMAScript语言构造需要的语义。这些算法并不是打算暗示任何具体实现的使用。事实上,这里也许有更高效的算法去实现指定的特性。
算法也许被显式的参数化,在这些案例中参数的名称和用法必须作为算法定义的一部分提高。
算法步骤也许被细分成多个连续的子步骤。子步骤需要用缩进表示,并且也许会进一步被划分成更小的缩进的子步骤。大纲编号约定被用作标识有小写字母字符标签的一级子步骤以及有小写罗马数字标签的二级子步骤。如果超过步骤3级,那么这些规则从第四级开始用数字标签进行重复。例如:
1.Top-level step
a.Substep.
b.Substep.
i.Subsubstep.
1.Subsubsubstep
a.Subsubsubsubstep
i.Subsubsubsubsubstep
一个步骤或者子步骤也许会使用“if”去断言它的子步骤的条件。在这样的案例中,这些子步骤只能适用于“if”断言为true的情况。如果一个步骤或者子步骤以单词“else”开始,那么表示这是之前的“if”断言的同一级的否定断言。
一个步骤也许会指定它的子步骤的迭代程序。
一个以“Assert:”开头的步骤断言一个它的算法里不变的条件。这样的断言被用作使算法不变量显式地展示,否则它将是隐式的。这样的断言不增加额外的语义需求,因此在实现中不需要被检查。它们被使用只是为了使算法更清晰。
对于任意形如“Let x be someValue”的值,算法步骤也许会声明命名别名。这些别名即可能通过x
也可能通过someValue
引用,它们指向同一个潜在的数据,并且修改其中任意一个对另一个都是可见的。那些想避免这样的类似引用的算法步骤需要显式地复制一份右值:即“Let x be a copy of someValue”创建了一个someValue
的浅复制。
一旦声明完毕,别名也许会在随后的任意步骤或者子步骤中被引用,但是它们也许不会在最高级步骤中被引用。别名也许会通过形如“Set x to someOtherValue”这样的形式被修改。
5.2.1 抽象操作(Abstract Operations)
为了促进它们在本规范的多个地方使用,一些算法,我们称之为抽象操作,在参数化的函数形式中中命名和书写,以便它们能够在其它算法中通过名称来引用。抽象操作通常是被通过一个功能化的应用风格引用,如OperationName(arg1
, arg2
)。一些抽象操作被当作像类规范里抽象的多态发送一样。这样的类似类的方法抽象操作通常通过一个方法应用风格被引用,如someValue
.OperationName(arg1
, arg2
)。
5.2.2 特定语法操作(Syntax-Directed Operations)
一个特定的语法操作是一个具有名称的操作,它的定义包含了一系列算法,每个算法与一个或者多个ECMAScript文法的产生式相关联。一个有多个可选定义的产生式通常对于每个可选部分都有一个独立的算法。当一个算法与一个文法产生式相关联的时候,它也许会引用这个产生式可选部分的终结符或者非终结符,就好像它们是这个算法的参数一样。当出现这种情况时,非终结符指向实际的源代码中与之匹配的可选部分的定义。
当一个算法与一个产生式的可选部分关联的时候,这个可选部分通常不会带上“[ ]” 文法注释。这样的注释只应该影响可选部分的语法识别,不应该对相关的可选部分的语义有影响。
Syntax-directed operations are invoked with a parse node and, optionally, other parameters by using the conventions on steps 1, 3, and 4 in the following algorithm:
特定语法操作同一个解析节点一起被调用,还可以在步骤1,3,4中使用这个约定的其它参数。
1. Let `status` be the result of performing SyntaxDirectedOperation of SomeNonTerminal.
2. Let `someParseNode` be the parse of some source text.
3. Perform SyntaxDirectedOperation of `someParseNode`.
4. Perform SyntaxDirectedOperation of `someParseNode` passing
"value" as the argument.
除非显式地指定,否则,所有相关联的产生式对于每个也许会被应用到这个产生式左值的非终结符的操作都有一个隐式的定义。如果存在的话,这个隐式的定义简单地再次对同样的参数运用这个相同的定义,对于这些相关联的产生式唯一的右值非终结符,随后返回处理结果。例如,假设一些算法有如下形式的步骤:“返回被解析的块的结果(Return the result of evaluating Block)”,并且这里有一个产生式:
Block :
{ StatementList }
但是解析操作并没有关联这个产生式的算法。那么在这样的案例中,解析操作隐式地包含了下面形式的关联:
运行时语义: 解析(Runtime Semantics: Evaluation)
Block : { StatementList }
1. Return the result of evaluating StatementList.
5.2.3 运行时语义(Runtime Semantics)
必须在运行时被调用的指定语义的算法就叫运行时语义。运行时语义通过抽象操作或者指定语法操作来定义。这样的算法必须返回一个完成记录。
5.2.3.1 隐式完成值(Implicit Completion Values)
<h5 align="center">表8:完成记录字段(Completion Record Fields)</h5>
完成类型是一个记录,用于解释某些执行非外部控制转移语句(例如break
, continue
, return
, throw
)运行时值和控制流的传播。
完成类型的值是记录值,它们的字段定义在表8中。这样的值被称为完成记录。
Filed | Value | 含义 |
---|---|---|
[[Type]] | normal, break, continue, return, throw其中的一个 | 完成值的类型 |
[[Value]] | 一个ECMAScript语言值或者空值 | 产生的值 |
[[Target]] | 任意ECMAScript字符串或者空值 | 指定的控制转移的目标标签/元素 |
本规范的算法常常隐式地返回一个[[Type]]值为normal的完成记录(见表8,译注:由于很多解释位于较后的章节,如这个定义就位于第6章,而且比较重要,所有对于某些这样的情况会把它提到前面来)。除非它是上下文中另外非常明显的部分,一个返回一个值的算法语句,那么这个值将不是一个完成值。例如:1. Return "Infinity".
与下面的是同一个含义:1. Return NormalCompletion("Infinity").
然而,如果一个“return”语句的值表达式是一个完成记录构造的字面量,那么完成记录的结果将被返回。如果这个值表达式是一个对抽象操作的调用,那么“return”语句简单地返回这个抽象操作产生的完成记录。
抽象操作完成(完成记录)被用作强调之前计算的完成记录被返回。完成(Completion)这个抽象操作接收一个参数,即完成记录(completionRecord),然后执行下面的步骤:
1. Assert: completionRecord is a Completion Record.
2. Return completionRecord as the Completion Record of this abstract operation.
一个在算法步骤中没有值的“return”语句与下面的是同样的意思:1. Return NormalCompletion(undefined).
对于任意的在一个上下文中没有显示地需要一个完整的完成记录值的引用,等价于一个显式地对完成记录的[[Value]]字段的引用,除非完成记录是一个打断/中断(abrupt)完成。
5.2.3.2 抛出一个异常(Throw an Exception)
描述抛出一个异常的算法步骤,例如:1. Throw a TypeError exception.
意思就是:1. Return Completion{[[Type]]: throw, [[Value]]: a newly created TypeError object, [[Target]]: empty}.
5.2.3.3 如果被打断则返回(ReturnIfAbrupt)
算法步骤说明或者等同于:1. ReturnIfAbrupt(argument).
意思就是(译注:abrupt completion就是上面提到的改变控制流如break
之类的语句,除了这些之外的就是普通的Completion Record):
1. If argument is an abrupt completion, return argument.
2. Else if argument is a Completion Record, let argument be argument.[[Value]].
算法步骤说明或者等同于:1. ReturnIfAbrupt(AbstractOperation()).
意思就是:
1. Let hygienicTemp be AbstractOperation().
2. If hygienicTemp is an abrupt completion, return hygienicTemp.
3. Else if hygienicTemp is a Completion Record, let hygienicTemp be hygienicTemp.[[Value]].
这里的hygienicTemp
是短暂的(临时的),并且只在ReturnIfAbrupt有关的步骤中中可见。
算法步骤说明或者等同于:1. Let result be AbstractOperation(ReturnIfAbrupt(argument)).
意思就是:
1. If argument is an abrupt completion, return argument.
2. If argument is a Completion Record, let argument be argument.[[Value]].
3. Let result be AbstractOperation(argument).
5.2.3.4 如果被打断则返回 缩写(ReturnIfAbrupt Shorthands)
对抽象操作和以?为前缀的指定语法操作的调用暗示着ReturnIfAbrupt
需要被应用到结果的完成记录中。例如,步骤:1. ? OperationName().
等价于下面的步骤:1. ReturnIfAbrupt(OperationName()).
相似的,对于程序方法的风格,步骤:1. ? someValue.OperationName().
等价于1. ReturnIfAbrupt(someValue.OperationName()).
相似的,前缀!被用作暗示下列的对于抽象或者指定语法操作的调用将不会返回一个打断的(abrupt)完成值,并且作为结果的完成记录的[[Value]]字段应该被用作替换操作的返回值,例如,步骤:1. Let val be ! OperationName().
等价于下面的步骤:
1. Let val be OperationName().
2. Assert: val is never an abrupt completion.
3. If val is a Completion Record, set val to val.[[Value]].
对于运行时语义的指定语法的操作通过在调用操作前替换!或者?来利用这个缩写。1. Perform ! SyntaxDirectedOperation of NonTerminal.
5.2.4 静态语义(Static Semantics)
上下文无关文法不能足够好的去表达所有定义的规则,不管是一个输入元素的流形成的一个合法的将被解析的ECMAScript脚本(Script)还是模块(Module)。在一些情况中,需要额外的规则通过使用ECMAScript算法约定或者散文要求(prose requirements)来展示。这样的规则总是与一个文法的产生式相关联,被称作产生式的静态语义。
静态语义规则拥有名称,并且通常用一个算法来定义。具有名称的静态语义规则与文法产生式相关联,对于每个可采用的具有名称的静态语义规则,一个包含多个可选部分定义的产生式通常会对每个可选部分定义一个独有的算法。
除非在本规范中其它指定的文法产生式可选部分隐式地包含一个叫做Contains的接收一个值为包含相关产生式的文法的终结符或者非终结符的symbol
参数静态语义规则的定义。默认的包含定义为:
1. For each child node child of this Parse Node, do
a. If child is an instance of symbol, return true.
b. If child is an instance of a nonterminal, then
i. Let contained be the result of child Contains symbol.
ii. If contained is true, return true.
2. Return false.
上面的定义是显式地重写了规范的产生式。
一个特殊的静态语义规则是早期(提前)错误规则(Early Error Rule)。早期错误规则定了早期错误条件(参见条款16),它们与具体的文法产生式相关联。大多数早期错误规则的解析不是在本规范的算法中显式地被调用。一个符合规范的实现必须在第一次解析脚本或者模块之前,验证所有被用作解析脚本或者模块的产生式的早期错误规则。如果违反了任意的早期错误规则,那么脚本或者模块就是不合法的,并且不能被解析执行。
5.2.5 数学操作(Mathematical Operations)
除非其它地方特别注明不包括无限并且不包括负0(为了与正0区分),数学操作,例如加,减,否定(逻辑非),乘,除以及随后在条款中定义的数学函数应总是被当作是对于数学中所有真实数字计算出来的准确的结果。本规范算法中的浮点运算包含显式地的步骤,它们对于处理无穷,有符号的0,以及舍入是必要的。如果一个数学操作或者函数被应用在一个浮点数上,那么它必须被当作应用到用浮点数表示的具体的数学值;这样的浮点数必须是有限的,并且如果它是+0或者-0的话,那么相应的数学值就是简简单单的0。
数学函数abx(x
)用来计算x
的绝对值,如果x
是负数(小于0),那么结果就是-x
,否则结果就是x
本身。
数学函数min(x1
, x2
, ..., xN
)计算从x
到xN
的最小值。数学函数max(x1
, x2
, ..., xN
)计算从x
到xN
的最大值。这些数学函数的域(译注:即定义域和值域)以及范围包括+∞和-∞。
符号“x modulo y”(译注:即x模y)(y
必须是有限的且是非0的)计算出一个值k
,它的符号与y
一致(或者是0),这样的k满足abs(k
) < abs(y
),以及能找到某个整数y,使得x
-k
= q
* y
。
The mathematical function floor(x) produces the largest integer (closest to positive infinity) that is not larger than x.
注意 floor(x) = x-(x modulo 1). (译注:即模运算是向0方向舍入)
6 ECMAScript数据类型和值(ECMAScript Data Types and Values)
本规范的算法操作的值每一个都有其相应的类型。最可能的值类型恰恰是那些定义在这个条款中的类型。类型又进一步分为ECMAScript语言类型(language types)以及规范类型(specification types)。
在本规范总,符号“Type(x
)”用来作为“the type of x”的简写,这里的“type”指向定义在本条款中的ECMAScript语言以及规范类型。当术语“empty”被使用时,就好像它正在命名一个值,这和说“no value of any type”是相等的(译注:即任何类型都没有这个值)。
6.1 ECMAScript语言类型(ECMAScript Language Types)
一个ECMAScript语言类型对应那些被使用ECMAScript语言的ECMAScript程序员直接操作的值。ECMAScript语言类型是Undefined, Null, Boolean, String, Symbol, Number, and Object。一个ECMAScript语言值是一个具有ECMAScript语言类型特征的值。
6.1.1 Undefined类型(The Undefined Type)
Undefined类型仅仅只有一个值,被称为undefined
。任何没有被分配一个值的变量的值就是undefined
。
6.1.2 Null类型(The Null Type)
Null类型仅仅只有一个值,被称为null
。
6.1.3 Boolean类型(The Boolean Type)
Boolean类型代表一个拥有两个值的逻辑的实体,它们被称为true
和false
。
6.1.4 String类型(The String Type)
String类型是所有0或者16bit无符号整数值(“elements”)的有顺序的序列的集合,最大的长度是2^53 - 1个元素的长度。String类型通常被用作在一个正在运行的ECMAScript程序上展示文本数据,在这样的案例中,String中的每个元素都被当作一个UTF-16码元(code unit)。每个元素都被当作这个序列中的一个占位。这些位置使用非负整数来进行索引。第一个元素(如果存在的话)在索引(index)0的位置,下一个元素(如果存在的话)在索引1的位置,以此类推。一个字符串的长度是它内部的元素(即16-bit值)的个数。空字符串的长度为0,因此没有元素。
ECMAScript操作解释String值的地方,每个元素被解释成单个的UTF-16码元。然而,ECMAScript不会对这个字符串的码元序列施加任何的限制或者需求,所以当按照UTF-16码元解释的时候,它们也许是不合规范的。不解释字符串内容的操作把它们当作没有任何差别的16-bit无符号整数。函数String.prototype.normalize
可以被用来显式地规范化一个字符串值。函数String.prototype.localeCompare
内部对字符串进行了规范化,但是除此之外的其它操作都没有隐式地规范化字符串。只有那些被显式地指定用来处理语言或者对语言环境敏感的操作才会产生语言敏感的结果。
注意 这个设计背后的基本原理是保证Strings的实现尽可能是简单和高效的。如果ECMAScript源文本在规范化的形式C内,那么字符串字面量也应当被认为是规范化的,只要它们不包含任何Unicode转移序列。
一些操作把字符串内容解释为UTF-16编码的Unicode码元。在这样的案例中,解释的过程是:
- 一个范围在0到0xD7FF的码元或者范围在0xE000到0xFFFF的码元被解释成一个相同值的码点(code point)。
- 一个两个码元的序列,第一个码元
c1
在范围0XD800到0XDBFF,第二个码元c2
在范围0xDC00到0xDFFF,这样的称为代理对,它们被解释为一个值为(c1
- 0xD800) * 0x400 + (c2
- 0xDC00) + 0x10000的码点(See 10.1.2)。 - 一个范围在0xD800到0xDFFF但是不属于代理对的码元,被解释为一个相同值的码点。
译注,如果对于Unicode不是很了解的话,推荐阅读每个JavaScript开发者都该懂的Unicode
6.1.5 Symbol类型(The Symbol Type)
Symbol类型是所有非字符串的也许被用作作为对象的属性的值的集合。
每个可能的Symbol值都是唯一的和不可变的。
每个Symbol值永远地保持一个与之关联的叫做[[Description]]的值,它要么是undefined
要么是一个字符串值。
6.1.5.1 著名的Symbol(Well-Known Symbols)
著名的symbols就是我们说的那些被本规范的算法显式地引用的内置Symbol值。它们通常被用作属性(propertied)的key,这些key的值为规范的算法提供了一种扩展。除非其它地方显式地说明,著名的symbol的值被所有域(realm)共享。
在本规范内,一个著名的symbol通过形如@@name的形式被引用,这里的name是表1中的某一个:
<h6 align="center" >表 1 著名的Symbol</h6>
Specification Name | [[Description]] | Value and Purpose |
---|---|---|
@@hasInstance | "Symbol.hasInstance" | 一个方法,决定一个构造函数对象是否能将一个对象识别为它的实例。由instance 操作的语义来调用。 |
@@isConcatSpreadable | "Symbol.isConcatSpreadable" | 一个Boolean值,如果为true,代表一个对象对于Array.prototype.concat 应该被压成扁平的再加入进去。(译注:比如a.concat 一个元素,如果这个元素为数组,会把这个数组的元素挨个push 到a 后面,这个时候这个元素的@@isConcatSpreadable就为true ,如果这个元素是一个对象,那么就把这个对象当成一个整体push 到a 后面,这个时候这个元素的@@isConcatSpreadable就为false ) |
@@iterator | "Symbol.iterator" | 一个方法,返回一个对象默认的迭代器(iterator)。由for-of 操作的语义来调用。 |
@@match | "Symbol.match" | 一个正则表达式方法,匹配正则表达式对应的字符串。由 String.prototype.match 调用。 |
@@replace | "Symbol.replace" | 一个正则表达式方法,替换匹配到的字符串中的子串。由String.prototype.replace 调用。 |
@@search | "Symbol.search" | 一个正则表达式方法,返回一个字符串中匹配这个正则表达式的位置的索引。由String.prototype.search 调用。 |
@@species | "Symbol.species" | 这是一个函数类型的属性,那些被用来创建派生对象的构造函数就拥有这个属性。 |
@@split | "Symbol.split" | 一个正则表达式方法,在指定的匹配这个正则表达式的地方分割这个字符串。 |
@@toPrimitive | "Symbol.toPrimitive" | 一个方法,将一个对象转换为对应的原始值(primitive value)。由ToPrimitive 方法调用。 |
@@toStringTag | "Symbol.toStringTag" | 这是一个String类型的属性,被用在一个对象在创建时默认的字符串描述上。通过内置的Object.prototype.toString 方法访问。 |
@@unscopables | *"Symbol.unscopables"* | 这是一个Object类型的属性,它自身以及继承来的属性的名称是在with 环境中对应的对象中被排除了的属性的名称。(译注:即with 的对象里有的属性,这个@@unscopables的对象里属性不应该包含这些属性。) |
6.1.6 Number类型(The Number Type)
Number类型刚好有18437736874454810627个(即$2^{64}$ - $2^{53}$ + 3)值,表示双精度64位格式的在IEEE标准中关于二进制浮点类型运算的IEEE 754-2008规范的值,除了9007199254740990 (即$2^{53}$ - 2)是一个IEEE规范中截然不同的“Not-a-Number”值(译注:可参考规范中的2.1.35,6.2节等等),被作为一个单独的NaN
值在ECMAScript中展示。(注意NaN
由程序表达式NaN
产生。)
注意:在一个Number值已经被存储后,位模式(bit pattern)也许可以通过一个ArrayBuffer或者SharedArrayBuffer观察到,但是这和Number值的内部表示一样,不是ECMAScript的实现所必须的。
这里有两种其它的特殊值,叫做正无穷和负无穷。为了简洁和说明目的,这些值也分别用符号+∞
和-∞
表示。(注意这两个无穷数由程序表达式+Infinity
(或者简单的Infinity
)和-Infinity
产生)
其它的18437736874454810624个值(即,$2^{64}$ - $2^{53}$)被称作有限数(finite numbers)。其中一半是正数,一半是负数;对于每个有限正数值,这里都有一个相应量级的负数值。
注意这里既有正0也有负0。为了简洁和说明的目的,这些值也分别用符号+0
和-0
表示。(注意这两个不同的零数字值由程序表达式+0
(或者简单的0
)和-0
产生。)
18437736874454810622(即$2^{64}$ - $2^{53}$ - 2)个有限非0值有下面两种类型:
18428729675200069632 (that is, 264-254) of them are normalized, having the form
其中的18428729675200069632(即$2^{64}$ - $2^{54}$)个值是被范式化/规范化(normalized)了的,它们是下面的形式:
$s × m × 2^e$
这里的s是+1或者-1,m是一个小于$2^{53}$但是不小于$2^{52}$的正数,e是一个正数,范围从-1074到971,前后都包含。
剩下的9007199254740990(即$2^{53} - 2$)个值是没有被范式化的,它们是下面的形式:
$s × m × 2^e$
这里的s是+1或者-1,m是一个小于$2^{52}$的正数,e是-1074。
注意Number类型能表示的所有的正数和负数它们的量级/指数都不超过$2^{53}$。(事实上,整数0有两种表示,+0
和-0
)
如果是非0的话,一个有限数有一个奇数的尾数那么它就是奇数,整数m用来表示这个尾数(即上面提到的两种形式之一)。否则,它就有一个偶数的尾数。
在本规范中,短语“the Number value for x
”里的x
刚好代表一个非0值的真实的数学量(也有可能是如π之类的无理数),也意味着一个Number值按照下面的方式被选择出来。首先考虑Number类型中所有的有限数的集合,除去-0,加上两个Number类型无法表示的值,被称为$2^{1024}$(即1 × $2^{53}$ $2^{1024}$)以及$-2^{1024}$(即-1 × $2^{53}$ $2^{1024}$)。然后选择这个集合中离x
最近的元素。如果有两个值一样接近,那么选择有偶数尾数的那一个。处于为此目的考虑,两个额外的值$2^{1024}$和$-2^{1024}$被认为是拥有相同的偶数尾数。最后,如果选择的是$2^{1024}$,用+∞替换它。如果选择的是$-2^{1024}$,用-∞替换它。如果选择的是+0
,只在x
小于0时才用-0替换它。除了上面提到的这些,任意其它的选择值是不会发生变化的。最后的结果就是x
的Number值。(这样就能刚好产生与IEEE 754-2008的“round to nearest, ties to even”行为模式相对应的值。)
一些ECMAScript操作符仅仅处理指定范围的整数,例如前后都包含的$-2^{31}$到$2^{31} - 1$。或者是0到$2^{16} - 1$的范围。这些操作符接收任意Number类型的值,但是首先会将它们转换成像上面提到的这些范围内的值。可以参考7.1节的数字转换操作。
6.1.7 Object类型(The Object Type)
一个对象逻辑上是一个属性的集合。每个属性要么是一个数据属性(data property),要么是一个访问器属性(accessor property):
- 一个数据属性关联一个ECMAScript语言值的key值以及一个Boolean属性的集合。
- 一个访问器属性关联一个或两个访问器函数的key值,一级一个Boolean属性的集合。访问器函数被用来存储或者检索与这个属性相关的ECMAScript语言值。
属性是用key值来识别的。一个属性的key值要么是一个ECMAScript String值,要么是一个Symbol值。所有的String和Symbol值,包括空字符串,都是合法的属性key值。当一个属性的key是String值的时候,这个属性的name是这个属性的key。
一个整数索引是一个字符串值的属性key,它是一个规范的数字String(canonical numeric String)(参考7.1.16)。它的数字值要么是+0
,要么是一个小于等于$2^{53}$-1的正数。一个数组索引是一个整数索引,它的数字值i的范围是+0 ≤ i < $2^{32}-1$。(译注:即Array(2**32)会报错:Uncaught RangeError: Invalid array length,而Array(2**32 - 1)不会
)
属性的key被用来访问属性以及它们的值。这里有两种对属性的访问:get和set。分别对应值的检索和赋值。通过get和set来进行属性访问既包括直接属于自己的属性,也包括通过属性继承关系从其它相关对象继承来的属性。继承的属性也可能是另一个对象的自身属性或者继承来的属性。一个对象的每个自身属性必须有一个key值来区分它和这个对象的其它的自身属性。
所有的对象都是逻辑上的属性集合,但是对象却有多种形式用来区分访问以及变化它们的属性的语义。普通的对象是对象的最常见形式,拥有默认的对象语义。一个外来对象是这样的对象形式,它的属性语义与默认语义的各个方面都有区别。
6.1.7.1 Property Attributes
本规范中的属性(Attributes)被用作定义和解释对象属性(Object properties)的状态。一个数据属性(data property)与表2中列出的属性的key值相关联。
<h6 align="center">表2 Attributes of a Data Property</h6>
Attribute Name | Value Domain | Description |
---|---|---|
[[Value]] | 任意的ECMAScript语言类型 | 访问属性时被检索到的值 |
[[Writable]] | Boolean | 如果为false ,任何尝试通过[[Set]]去改变这个属性的[[Value]]属性的ECMAScript代码都不会成功。 |
[[Enumerable]] | Boolean | 如果为true ,这个属性被for-in枚举时将会是可枚举的(参考13.7.5)。否则,这个属性就是不可枚举的。 |
[[Configurable]] | Boolean | 如果为false ,任何尝试删除这个属性,把这个属性改为访问器属性,或者改变它的除了[[Value]]之外的属性,或者改变它的[[Writable]]为false 的操作都会失败。 |
一个访问器属性accessor property)与表3中列出的属性的key值相关联。
<h6 align="center">表3 Attributes of an Accessor Property</h6>
Attribute Name | Value Domain | Description | |
---|---|---|---|
[[Get]] | Object\ | Undefined | 如果这个值是一个对象,那么它必须是一个函数对象。在每次访问这个属性的时候,这个函数的内置[[Call]]方法(下面的表6中)将会被调用,同时会向这个方法传入一个空的arguments。 |
[[Set]] | Object\ | Undefined | 如果这个值是一个对象,那么它必须是一个函数对象。在每次设置这个属性的时候,这个函数的内置[[Call]]方法(下面的表6中)将会被调用,同时会向这个方法传入包含所赋的值的arguments,作为这个arguments的唯一参数。[[Set]]内置方法也许会对后续的[[Get]]内置方法调用产生的返回值产生影响,但不是必须的。 |
[[Enumerable]] | Boolean | 如果为true ,这个属性被for-in枚举时将会是可枚举的(参考13.7.5)。否则,这个属性就是不可枚举的。 |
|
[[Configurable]] | Boolean | 如果为false ,任何尝试删除这个属性,把这个属性改为数据属性,或者改变它的其它attributes的操作都会失败。 |
如果一个属性的attributes的初始值没有被本规范显式地指定的时候,那么使用在表4中定义的默认值:
<h6 align="center">表4 Default Attribute Values</h6>
Attribute Name | Default Value |
---|---|
[[Value]] | undefined |
[[Get]] | undefined |
[[Set]] | undefined |
[[Writable]] | false |
[[Enumerable]] | false |
[[Configurable]] | false |
6.1.7.2 对象的内置方法和内置槽(Object Internal Methods and Internal Slots)
在ECMAScript中,对象的实际语义是通过算法来调用内置方法指定的。在ECMAScript引擎中的每个对象都与一系列的定义它的运行时行为的内置方法相关联。这些内置方法不属于ECMAScript语言的一部分。通过本规范定义它们的部分仅仅是为了解释和说明的目的。然而,在ECMAScript具体实现中的每个对象必须表现得像这些内置方法与它关联了一样。其中的准确的行为由实现来决定。
内置方法(Internal method)的名称是多种多样的。这意味着当一个常见的内置方法被调用的时候,不同的对象值也许会运行不同的算法。内置方法被调用时实际的对象成为这个调用的“目标”(“target”)。如果在运行时一个算法的实现尝试去使用一个对象不支持的内置方法,一个TypeError
将会被抛出。
内置槽(Internal slots)对应相关联对象的内部状态,被ECMAScript规范中不同的算法使用。内置槽不是对象的属性,也不会被继承。根据规范中具体的内置槽,这样的内部状态也许包含任意ECMAScript语言类型的值或者指定的ECMAScript规范类型的值。除非显式地指定,否则内置槽作为创建一个对象的一部分过程被分配,并且也许不能被动态地添加到对象上。除非显式地指定,否则一个内置槽的初始值是undefined
。本规范内不同的算法都会创建有内置槽的对象。然而,ECMAScript语言不提供直接的方法去访问一个对象的内置槽。
本规范内的内置方法和内置槽使用闭合的双方括号[[]]来标识。
下方的表5总结了被规范使用的适用于所有对象的创建或者被ECMAScript代码操作的至关重要的内置方法。每个对象对于所有至关重要的算法都必须有相应的算法。然而,所有的对象没有必要对那些方法使用相同的算法。
下面的表5中的 “Signature”列以及其它相似的表格描述了每个内置方法的调用模式。调用模式总是包含一个括起来的描述参数名的列表。如果一个参数名与ECMAScript类型的名字一样,那么代表描述的是参数值需要的类型。如果一个内置方法显式地返回了一个值,它的参数列表随后就会跟着一个“→”符合,以及返回值的类型。在signature中使用的类型的名字指向在条款6中定义的类型,另外还增加了一些下面的名称。“any”代表这个值也许是任意的ECMAScript语言值。一个内置方法会隐式地返回一个完成记录。除了它的参数,一个内置方法还总是会访问这个方法调用的对象的目标(即前面提到的target)。
<h6 align="center">表5 Essential Internal Methods</h6>
Internal Method | Signature | Description | |
---|---|---|---|
[[GetPrototypeOf]] | ( ) → Object | Null | 确定为这个对象提供继承的属性的对象。一个null 值代表没有继承的属性。 |
[[SetPrototypeOf]] | (Object | Null) → Boolean | 将这个对象与提供继承的属性的对象相关联。传递null 表示没有继承的属性。返回true 表示操作成功,返回false 表示操作失败。 |
[[IsExtensible]] | ( ) → Boolean | 决定是否允许添加额外的属性到这个对象上。 | |
[[PreventExtensions]] | ( ) → Boolean | 控制一个新的属性是否能加到这个对象上。返回true 表示操作成功,返回false 表示操作失败。 |
|
[[GetOwnProperty]] | (propertyKey) → Undefined \ | Property Descriptor | 返回这个对象的一个自身属性(own property)的属性描述符,它的key为propertyKey,或者undefined(如果没有这样的属性存在的话)。 |
[[DefineOwnProperty]] | (propertyKey, PropertyDescriptor) → Boolean | 创建或者改变自身属性,它的key为propertyKey,它的状态为PropertyDescriptor。返回true 表示属性被成功创建/更新,返回false 表示属性不能被创建/更新。 |
|
[[HasProperty]] | (propertyKey) → Boolean | 返回一个Boolean值,代表这个对象是否已经有一个自身的或者继承的key为propertyKey的属性。 | |
[[Get]] | (propertyKey, Receiver) → any | 返回这个对象里key值为propertyKey的属性的值。如果任何的ECMAScript代码必须被运行来检索这个属性值,Receiver就会作为解析代码时的this 值。 |
|
[[Set]] | (propertyKey, value, Receiver) → Boolean | 设置这个对象中的key为propertyKey的属性的值为value。如果任何的ECMAScript代码必须被运行来检索这个属性值,Receiver就会作为解析代码时的this 值。返回true 表示这个属性能被设置,返回false 表示不能被设置。 |
|
[[Delete]] | (propertyKey) → Boolean | 移除这个对象的key值为propertyKey的自身属性。返回false 表示这个属性没有被移除,仍然存在。返回true 表示已经被移除,不再存在。 |
|
[[OwnPropertyKeys]] | ( ) → List of propertyKey | 返回一个一个List,这个List里的元素都来自这个对象的自身属性的key。 |
下方的表6总结了也许会被当作函数来调用的对象的额外的至关重要的内置方法。一个函数对象是一个支持[[Call]]内置方法的对象。一个构造器(也被称为构造函数)是一个支持[[Construct]]内置方法的函数对象。
<h6 align="center">表6 Additional Essential Internal Methods of Function Objects</h6>
Internal Method | Signature | Description | |
---|---|---|---|
[[Call]] | (any, a List of any) → any \ | Null | 执行这个对象相关联的代码。通过一个函数表达式来调用。通过调用表达式,传递给内置方法的arguments是一个this 值以及一个包含传递给自己函数的参数的列表。实现这个内置方法的对象被称为可调用的(callable)。 |
[[Construct]] | (a List of any, Object) → Object \ | Null | 通过new 或者super 操作符创建一个对象。传递给这个内置方法的第一个参数是一个包含操作符的参数的列表。第二个参数是new 操作符初始化时应用的对象。实现这个内置方法的对象被称为构造函数(constructors)。一个函数对象不一定是构造函数,这样的非构造函数的函数对象没有[[Construct]]内置方法。(译注:比如new Window()会抛出Uncaught TypeError: Illegal constructor ) |
这些普通对象的至关重要的内置方法的语义和标准的外来对象在条款9中指出。如果一个外来对象的任何内置方法的使用不被实现所支持,那么尝试使用这个用法时必须抛出一个TypeError
异常。
6.1.7.3 至关重要的内置方法的不变量(Invariants of the Essential Internal Methods)
ECMAScript引擎中的对象的内置方法必须符合下方指定的不变量列表。普通的ECMAScript对象以及本规范中标准的外来对象维护这些不变量。ECMAScript代理(Proxy)对象通过对[[ProxyHandler]]对象被调用的结果的运行时检查来维护这些不变量。
任何提供外来对象的实现也必须维护这些对象的不变量。违反这些不变量也许会造成ECMAScript代码出现不可预测的行为以及发生安全问题。然而,一个实现对于违反不变量的行为在内存安全问题上绝对不能妥协。
一个实现必须不允许这些不变量在任何例如提供实现了至关重要的内置方法的功能但是没有执行它们的不变量的可选接口的行为中被规避。
定义:
- 一个内置方法的target是一个对象,这个对象的对应的内置方法会被调用。
- 如果一个target被观察到它的[[IsExtensible]]内置方法返回
false
或者[[PreventExtensions]]返回true
,那么它是不可扩展的。 - 一个不存在的属性是指那些在不可扩展的target的自身属性上不存在的属性。
- 所有引用SameValue(译注:即判断两个值是否相等)的地方都根据SameValue算法。
[[GetPrototypeOf]] ( )
- 返回值的类型必须是Object或者Null。
- 如果target是不可扩展的,并且[[GetPrototypeOf]]返回了一个值v,那么任何将来的对[[GetPrototypeOf]]的调用都应该返回v的SameValue。
注意1: 一个对象的原型链的长度应该是有限的(也就是说,从任意对象开始,递归地对结果应用[[GetPrototypeOf]]内置方法最终应该得到null)。然而,如果这个原型链包含任意的不使用普通对象的[[GetPrototypeOf]]定义的外来对象,那么作为一个对象的不变量水平,这个要求不是强制的。当访问对象属性的时候,这样的一个环形的原型链也许最终会导致无限循环。
[[SetPrototypeOf]] (V)
- 返回值的类型必须是Boolean。
- 如果target是不可扩展的,[[SetPrototypeOf]]必须返回false,除非V是target观察到的[[GetPrototypeOf]]值的SameValue。
[[IsExtensible]] ( )
- 返回值的类型必须是Boolean。
- 如果[[IsExtensible]]返回false,所有将来的在target上的对[[IsExtensible]]的调用都必须返回false。
[[PreventExtensions]] ( )
- 返回值的类型必须是Boolean。
- 如果[[PreventExtensions]]返回false,所有将来的在target上的对[[IsExtensible]]的调用都必须返回false,并且现在开始target被认为是不可扩展的。
[[GetOwnProperty]] ( )
- 返回值的类型必须是Property Descriptor或者Undefined。
- If the Type of the return value is Property Descriptor, the return value must be a complete property descriptor (see 6.2.5.6).
- 如果返回值的类型是Property Descriptor,那么返回值必须是一个完整的property descriptor(参考6.2.5.6)。
- 如果一个属性P被描述为一个含有Desc的数据属性。访问器 的[[Value]]等于v,访问器的[[Writable]]以及[[Configurable]]为false,那么对于访问器的[[Value]]属性,必须返回SameValue。将来对这个属性的[[Value]]属性的调用变成[[GetOwnProperty]] ( P )。
- 如果P的除了[[Writable]]之外的属性随着时间发生了变化或者这个属性消失了,那么P的[[Configurable]]属性必须变成true。
- 如果[[Writable]]属性从false变成了true,那么[[Configurable]]属性必须变成true。
- 如果target是不可扩展的,并且P是不存在的,那么所有将来在target上对[[GetOwnProperty]] (P)的调用必须把P描述为不存在的(即[[GetOwnProperty]] (P)必须返回undefined)。
注意2: 作为第三个不变量的结论,如果一个属性被描述为一个数据属性并且随着时间它返回不同的值,那么访问器的[[Writable]]和[[Configurable]]属性必须是true,即使没有机制去改变通过其它内置方法暴露出来的值。
[[DefineOwnProperty]] ( P, Desc)
- 返回值的类型必须是Boolean。
- 如果P之前已经被观察为target的一个不可配置的自身属性,[[DefineOwnProperty]]必须返回false,除非:
- P是一个不可配置的可写的自身数据属性。一个不可配置的可写数据属性能被改变为一个不可配置的不可写的数据属性。
- 所有在访问器中的属性都是P的属性的SameValue。
- 如果target是不可扩展的并且P是一个不存在的自身属性,[[DefineOwnProperty]] (P, Desc)必须返回false。也就是说,一个不可扩展的对象不能扩展新的属性。
[[HasProperty]] ( P )
- 返回值的类型必须是Boolean。
- 如果P之前被观察到是target的一个不可配置的数据或者访问器自身属性,[[HasProperty]]必须返回true。
[[Get]] (P, Receiver)
- 如果P之前被观察到是target的一个value为v的不可配置且不可写的自身数据属性,那么[[Get]]必须返回SameValue。
- 如果P之前被观察到是[[Get]]属性是undefined的target的一个不可配置的自身访问器属性,那么[[Get]]操作必须返回undefined。
[[Set]] ( P, V, Receiver)
- 返回值的类型必须是Boolean。
- 如果P之前被观察到是target的一个value为v的不可配置且不可写的自身数据属性,那么[[Set]]必须返回false,除非V是P的[[Value]]属性的SameValue。
- 如果P之前被观察到[[Set]]属性是undefined 的target的是一个不可配置的自身访问器属性,那么[[Set]]操作必须返回undefined。
[[Delete]] ( P )
- 返回值的类型必须是Boolean。
- 如果P之前被观察到是target的一个不可配置的自身数据属性或者访问器属性,[[Delete]]必须返回false。
[[OwnPropertyKeys]] ( )
- 返回值必须是一个List。
- 返回的List中的每个元素的类型要么是String,要么是Symbol。
- 返回的List必须至少包含之前观察到的所有的不可配置的自身属性。
- 如果这个对象是不可扩展的,那么返回的List必须只能包含这个对象的所有通过[[GetOwnProperty]]观察到的自身属性的key。
[[Construct]] ( )
- 返回值的类型必须是Object。
6.1.7.4 著名的内部对象(Well-Known Intrinsic Objects)
著名的内部函数是那些被本规范的算法显式地引用的内置对象,在这些函数中通常拥有基于特定域(realm-specific)下的特性。除非另有说明,否则每个内部对象在每个域中都实际对应一个相似对象的集合。
在本规范中,一个像%name%这样的引用就表示关联到当前域的内部对象的对应的name。当前域的确定以及它的内部情况在8.3节中描述。著名/常见的内部对象在下面的表7中列出。
<h6 align="center">表7 Well-known Intrinsic Objects</h6>
Intrinsic Name | Global Name | ECMAScript Language Association |
---|---|---|
%Array% | Array | Array构造函数(参考22.1.1) |
%ArrayBuffer% | ArrayBuffer | ArrayBuffer构造函数(参考24.1.2) |
%ArrayBufferPrototype% | ArrayBuffer.prototype | %ArrayBuffer%的prototype数据属性的初始值 |
%ArrayIteratorPrototype% | Array迭代器的prototype对象(参考22.1.5) | |
%ArrayPrototype% | Array.prototype | %Array%的prototype数据属性的初始值(参考22.1.3) |
%ArrayProto_values% | Array.prototype.values | %ArrayPrototype%的prototype数据属性的初始值(参考22.1.3.30) |
%AsyncFunction% | 异步的函数对象(async function )的构造器(参考25.5.1) | |
%AsyncFunctionPrototype% | %AsyncFunction%的prototype数据属性的初始值 | |
%Atomics% | Atomics | Atomic对象(参考24.4) |
%Boolean% | Boolean | Boolean构造函数(参考19.3.1) |
%BooleanPrototype% | Boolean.prototype | %Boolean%的prototype数据属性的初始值(参考19.3.3) |
%DataView% | DataView | DataView构造函数(参考24.3.2) |
%DataViewPrototype% | DataView.prototype | %DataView%的prototype数据属性的初始值 |
%Date% | Date | Date构造函数(参考20.3.2) |
%DatePrototype% | Date.prototype | %Date%的prototype数据属性的初始值 |
%decodeURI% | decodeURI | decodeURI函数(参考18.2.6.2) |
%decodeURIComponent% | decodeURIComponent | decodeURIComponent函数(参考18.2.6.3) |
%encodeURI% | encodeURI | encodeURI函数(参考18.2.6.4) |
%encodeURIComponent% | encodeURIComponent | encodeURIComponent函数(参考18.2.6.5) |
%Error% | Error | Error构造函数(参考19.5.1) |
%ErrorPrototype% | Error.prototype | %DataView%的prototype数据属性的初始值 |
%eval% | eval | eval函数(参考18.2.1) |
%EvalError% | EvalError | EvalError构造函数(参考19.5.5.1) |
%EvalErrorPrototype% | EvalError.prototype | %EvalError%的prototype数据属性的初始值 |
%Float32Array% | Float32Array | Float32Array构造函数(参考22.2) |
%Float32ArrayPrototype% | Float32Array.prototype | %Float32Array%的prototype数据属性的初始值 |
%Float64Array% | Float64Array | Float64Array构造函数(参考22.2) |
%Float64ArrayPrototype% | Float64Array.prototype | %Float64Array%的prototype数据属性的初始值 |
%Function% | Function | Function构造函数(参考19.2.1) |
%FunctionPrototype% | Function.prototype | %Function%的prototype数据属性的初始值 |
%Generator% | %Generator%的prototype数据属性的初始值 | |
%GeneratorFunction% | generator对象的构造函数(参考25.2.1) | |
%GeneratorPrototype% | %Generator%的prototype数据属性的初始值 | |
%Int8Array% | Int8Array | Int8Array构造函数(参考22.2) |
%Int8ArrayPrototype% | Int8Array.prototype | %Int8Array%的prototype数据属性的初始值 |
%Int16Array% | Int16Array | Int16Array构造函数(参考22.2) |
%Int16ArrayPrototype% | Int16Array.prototype | %Int16Array%的prototype数据属性的初始值 |
%Int32Array% | Int32Array | Int32Array构造函数(参考22.2) |
%Int32ArrayPrototype% | Int32Array.prototype | %Int32Array%的prototype数据属性的初始值 |
%isFinite% | isFinite | isFinite函数(参考18.2.2) |
%isNaN% | isNaN | isNaN函数(参考18.2.3) |
%IteratorPrototype% | 一个对象,所有的内置对象的迭代器对象间接地都从这个对象继承而来。 | |
%JSON% | JSON | JSON对象(参考24.5) |
%Map% | Map | Map构造函数(参考23.1.1) |
%MapIteratorPrototype% | Map迭代器对象的原型(参考23.1.5) | |
%MapPrototype% | Map.prototype | %Map%的prototype数据属性的初始值 |
%Math% | Math | JSON对象(参考20.2) |
%Number% | Number | Number构造函数(参考20.1.1) |
%NumberPrototype% | Number.prototype | %Number%的prototype数据属性的初始值 |
%Object% | Object | Object构造函数(参考19.1.1) |
%ObjectPrototype% | Object.prototype | %Object%的prototype数据属性的初始值(参考19.1.3) |
%ObjProto_toString% | Object.prototype.toString | %Object%的toString数据属性的初始值(参考19.1.3.6) |
%ObjProto_valueOf% | Object.prototype.valueOf | %Object%的valueOf数据属性的初始值(参考19.1.3.7) |
%parseFloat% | parseFloat | parseFloat函数(参考18.2.4) |
%parseInt% | parseInt | parseInt函数(参考18.2.5) |
%Promise% | Promise | Promise构造函数(参考25.4.3) |
%PromisePrototype% | Promise.prototype | %Promise%的prototype数据属性的初始值 |
%Proxy% | Proxy | Proxy构造函数(参考26.2.1) |
%RangeError% | RangeError | RangeError构造函数(参考19.5.2.2) |
%RangeErrorPrototype% | RangeError.prototype | %RangeError%的prototype数据属性的初始值 |
%ReferenceError% | ReferenceError | ReferenceError构造函数(参考19.5.5.3) |
%ReferenceErrorPrototype% | ReferenceError.prototype | %ReferenceError%的prototype数据属性的初始值 |
%Reflect% | Reflect | Reflect对象(参考26.1) |
%RegExp% | RegExp | RegExp构造函数(参考21.2.3) |
%RegExpPrototype% | RegExp.prototype | %RegExp%的prototype数据属性的初始值 |
%Set% | Set | Set构造函数(参考23.2.1) |
%SetIteratorPrototype% | Set迭代器对象的prototype(参考23.2.5) | |
%SetPrototype% | Set.prototype | %Set%的prototype数据属性的初始值 |
%SharedArrayBuffer% | SharedArrayBuffer | SharedArrayBuffer构造函数(参考24.2.2) |
%SharedArrayBufferPrototype% | SharedArrayBuffer.prototype | %SharedArrayBuffer%的prototype数据属性的初始值 |
%String% | String | String构造函数(参考21.1.1) |
%StringIteratorPrototype% | String迭代器对象的prototype(参考21.1.5) | |
%StringPrototype% | String.prototype | %String%的prototype数据属性的初始值 |
%Symbol% | Symbol | Symbol构造函数(参考19.4.1) |
%SymbolPrototype% | Symbol.prototype | %Symbol%的prototype数据属性的初始值(参考19.4.3) |
%SyntaxError% | SyntaxError | SyntaxError构造函数(参考19.5.5.4) |
%SyntaxErrorPrototype% | SyntaxError.prototype | %SyntaxError%的prototype数据属性的初始值 |
%ThrowTypeError% | 一个函数对象,无条件的抛出一个%TypeError%的实例 | |
%TypedArray% | 所有的typed Array构造函数的父类(参考22.2.1) | |
%TypedArrayPrototype% | %TypedArray%的prototype数据属性的初始值 | |
%TypeError% | TypeError | TypeError构造函数(参考19.5.5.5) |
%TypeErrorPrototype% | TypeError.prototype | %TypeError%的prototype数据属性的初始值 |
%Uint8Array% | Uint8Array | Uint8Array构造函数(参考22.2) |
%Uint8ArrayPrototype% | Uint8Array.prototype | %Uint8Array%的prototype数据属性的初始值 |
%Uint8ClampedArray% | Uint8ClampedArray | Uint8ClampedArray构造函数(参考22.2) |
%Uint8ClampedArrayPrototype% | Uint8ClampedArray.prototype | %Uint8ClampedArray%的prototype数据属性的初始值 |
%Uint16Array% | Uint16Array | Uint16Array构造函数(参考22.2) |
%Uint16ArrayPrototype% | Uint16Array.prototype | %Uint16Array%的prototype数据属性的初始值 |
%Uint32Array% | Uint32Array | Uint32Array构造函数(参考22.2) |
%Uint32ArrayPrototype% | Uint32Array.prototype | %Uint32Array%的prototype数据属性的初始值 |
%URIError% | URIError | URIError构造函数(参考19.5.5.6) |
%URIErrorPrototype% | URIError.prototype | %URIError%的prototype数据属性的初始值 |
%WeakMap% | WeakMap | WeakMap构造函数(参考23.3.1) |
%WeakMapPrototype% | WeakMap.prototype | %WeakMap%的prototype数据属性的初始值 |
%WeakSet% | WeakSet | WeakSet构造函数(参考23.4.1) |
%WeakSetPrototype% | WeakSet.prototype | %WeakSet%的prototype数据属性的初始值 |
6.2 ECMAScript规范类型(ECMAScript Specification Types)
译注:本小节大部分都是算法,所以只是翻译一下各小节最前面的文字介绍,即每一小节的后面还有很多相应的算法,对这些具体算法有兴趣可以自己再研究研究。
一个规范类型对应那些被用在算法中去描述ECMAScript语言结构/构造以及ECMAScript语言类型的元数据。规范类型包括,Reference, List, Completion, Property Descriptor, Lexical Environment, Environment Record以及Data Block。规范类型的值是规范里才有的,在ECMAScript实现中没有必要与任何具体的实体相关联/对应。规范类型的值也许被用来描述ECMAScript表达式解析后的中间结果,但是这样的值不能被存储作为ECMAScript语言变量的对象属性或值的一部分。
6.2.1 List和Record规范类型(The List and Record Specification Types)
List类型被用来解释在new
表达式中对于argument lists(参考12.3.6)的解析,以及在函数调用中,或者在其它需要一个简单的有序的值的list的算法的地方。List类型的值是简单的包含各自list元素的有序序列。这些序列可能是任意的长度。一个list中的元素可以通过0到某个区间内的索引来随机访问。为了记数方便,一个类数组语法可以被用来访问List的元素。例如,arguments
[2]是arguments List中第三个元素的简写。
为了本规范的记法方便,可以用一个字面量语法来表示一个新的List值。例如,« 1, 2 »定义了一个有2个元素的List值,每个元素都被实例化为了一个具体的值。一个新的空的List可以用« »表示。
Record类型被用来描述在本规范算法内的数据的聚合。一个Record类型的值包含一个或者多个命名的字段。每个字段的值要么是一个ECMAScript值,要么是一个用一个关联Record类型的名称表示的抽象值。字段名总是双方括号闭合的,例如[[Value]]。
为了本规范的方便,一个类似对象字面量的语法被用来表示一个Record值。例如,{[[Field1]]: 42, [[Field2]]: false
, [[Field3]]: empty}定义了一个包含3个字段的Record值,其中的每一个都被实例化为了一个具体的值。字段名的顺序是不重要的。任何没有被显式地列出的字段都被认为是不存在的。
在规范的文本和算法中,点符号也许会被用来指向一个具体的一个Record值的某个特定字段。例如,如果R是一个在之前的段落中出现的record,那么R.[[Field2]]代表“R中名称叫[[Field2]]的字段”的简写。
常见的使用Record字段组合模式的地方也许是被命名了的,这个名称用在一个Record字面量前作为前缀,来定义描述的具体的聚合类型。例如: PropertyDescriptor{[[Value]]: 42, [[Writable]]: false
, [[Configurable]]: true
}。
6.2.2 Set和关系规范类型(The Set and Relation Specification Types)
Set类型被用来解释在内存模型中无序元素的集合。Set类型的值是简单的元素的集合,其中没有任何元素出现超过2次。元素可以从Set中添加或者删除。不同的Set可以是联合的(unioned),分割的或者除去的。(译注:即数学中集合之间的关系,并,交,补等。)
关系(Realation)类型被用来解释在Set上的约束。一个关系类型的值是它的的值域中有序对的集合。例如,一个在event上的关系是一个有序的的event对的集合。对于一个关系R
以及在R
的值域中的两个值a
和b
,a R b
是有序对(a, b)
是R
的成员的简写。(译注,这些在离散数学中应该都有相应的介绍)
6.2.3 完成记录规范类型(The Completion Record Specification Type)
见前面的5.2.3.1。
6.2.4 引用规范类型(The Reference Specification Type)
注意:引用类型被用来解释像
delete
,typeof
,赋值等操作符以及super
关键字,以及其它语言特性的行为。例如,赋值操作左边的操作数应该是一个引用。
一个引用是一个解析后的名称或者属性绑定。一个引用包含3个组件,基础的值组件(value component),引用的名称组件(name component),以及Boolean值的是否引用严格模式的flag。基础的值组件要么是undefined
,要么是一个对象,Boolean,String,Symbol,Number,或者一个环境记录(Environment Record)。一个undefined
的基础值组件表示这个引用不能被解析为一个绑定。引用的名称组件是一个String或者Symbol值。
一个超引用(Super Reference)是一个被用来表示一个用super
关键字表示的名称绑定的引用。一个超引用有额外的thisValue组件,它的基础值组件将永远不能是一个环境记录。
6.2.5 属性描述符规范类型(The Property Descriptor Specification Type)
属性描述符类型被用来解释对对象属性的操作和物化。属性描述符的值是Record。每个字段的名称是一个属性名称,并且它的值是一个在6.1.7.1中相对应的属性值。此外,任何的字段都可以被展示或者省略。在本规范内使用的对属性描述符的record的标签字面量描述模式名称为“PropertyDescriptor”。
属性描述符的值也许会进一步在基于已存在的某些字段上依据数据属性描述符和访问器属性描述符来进行分类。一个数据属性描述符是包含[[Value]]或者[[Writable]]的任意字段名的类型。一个访问器属性描述符包含是[[Get]]或者[[Set]]的任意字段名的类型。任何一个属性描述符都包含[[Enumerable]]和[[Configurable]]字段名。一个属性描述符的值也许既不是一个数据属性描述符,也不是一个访问器属性描述符。然而,也有可能都是。一个一般的属性描述符是一个既不是数据属性描述符也不是访问器属性描述符的值。一个完全被填充的属性描述符是一个包含所有在表2或者表3中相应属性的字段的访问器属性描述符或者一个数据属性描述符。
6.2.6 词法环境和环境记录规范类型(The Lexical Environment and Environment Record Specification Types)
The Lexical Environment and Environment Record types are used to explain the behaviour of name resolution in nested functions and blocks. These types and the operations upon them are defined in 8.1.
词法环境(Lexical Environment)和环境记录(Environment Record)类型被用来解释在嵌套的函数和块中的名称解析行为。在这些之上的类型和操作定义在8.1中。
6.2.7 Data Blocks
数据块规范类型被用来描述一个独特的且不可变的基于字节(8bit)数字值序列。一个数据块值用一个固定的字节数字来创建,它们的每一个的初始值都为0。
为了本规范的方便,一个类数组语法被用来访问一个数据块值的自己的字节。这个符号用一个从0开始的索引的字节序列整数来表示一个数据块值。例如,如果db
是一个5个字节的数据块值,那么db
[2]就能被用来访问它的第三个字节。
一个驻留在内存中的数据块能被多个代理并发地引用,我们特指这样的叫做共享数据块。一个共享数据块有一个没有地址的(address-free)标识(出于为了平等地测试共享数据块的值的目的):它并不是挂在任意进程中这个块对应的虚拟地址上,而是内存中的这个代表这个块的地址。只有当它们包含的地址的集合是相等的,两个数据块才是相等的。否则,它们就是不相等的,它们包含的地址的集合的交叉为空。最后,共享数据块与数据块是有区别的。
The events form a candidate execution, on which the memory model acts as a filter. Please consult the memory model for full semantics.
共享数据块的语义使用内存模型中的共享数据块事件来定义。下方的抽象操作介绍了共享数据块事件以及在内存模型上解析语义和事件语义的接口的行为。事件形成了一个候选执行,内存模型扮演了一个过滤器的角色。请查看内存模型来了解更多的语义。
结语
到这里就暂时告一段落了,虽然在规范的中段和后段还有很多需要我们去学习的,以后经验丰富一点再看看能不能继续翻译吧。当然如果有人受此启发愿意去翻译,甚至是翻译css和html的规范那就更好了,W3C的规范有中文版,但是只有最前面1章,很久都没有更新了。
在最后笔者只是大致的看了一下有没有特别严重的比如排版错误之类的,翻译过程中肯定还存在很多问题,不管是翻译还是理解,都希望大家能够多多包涵,也希望大家能够指出错误,共同进步~
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。